package com.yanqu.road.server.manager.activity.horserun;

import com.yanqu.road.dao.impl.activity.horserun.cross.CrossHorseRunTrackDataDaoImpl;
import com.yanqu.road.dao.impl.activity.horserun.cross.CrossHorseRunUnionDataDaoImpl;
import com.yanqu.road.dao.impl.activity.horserun.cross.CrossHorseRunUserDataDaoImpl;
import com.yanqu.road.dao.impl.activity.horserun.cross.CrossHorseRunZoneRoundRankDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.horserun.config.HorseRunRaceCourseConfig;
import com.yanqu.road.entity.activity.horserun.cross.*;
import com.yanqu.road.entity.activity.horserun.entity.HorseRunTrackPartData;
import com.yanqu.road.entity.enums.activity.horserun.eHorseRunAttrEnum;
import com.yanqu.road.entity.enums.activity.horserun.eHorseRunRacingZoneEnum;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.log.cross.horserun.LogHorseRunRacingResult;
import com.yanqu.road.entity.log.cross.horserun.LogHorseRunUnionCourseLevelUp;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.rank.yrank.UserYRank;
import com.yanqu.road.entity.task.args.UnionRiseRankArgs;
import com.yanqu.road.entity.union.UnionBaseInfo;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroup;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroupUnion;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroupUser;
import com.yanqu.road.logic.activity.horserun.HorseRunConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.HorseRunProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.ActivityMgr;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.union.activitygroup.Cross2UnionActivityGroupMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manager.yrank.CrossYRankMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.mina.util.ConcurrentHashSet;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 小马快跑活动对象
 */

public class CrossHorseRunActivity {

    private int groupId;

    private int activityId;

    //商会数据
    private Map<String, CrossHorseRunUnionData> unionDataMap;
    //玩家数据
    private Map<Long, CrossHorseRunUserData> userDataMap;
    //赛道数据
    private Map<Integer,Map<Integer, CrossHorseRunTrackData>> trackDataMap;
    //排行 map key:<day<zone<data
    private Map<Integer,Map<Integer,List<CrossHorseRunZoneRoundRankData>>> rankDataListMap;
    //排行 map key:<day<zone<data
    private Map<Integer,Map<Integer,Map<Long,CrossHorseRunZoneRoundRankData>>> rankDataMapMap;

    private Random random = new Random();

    public CrossHorseRunActivity(int activityId, int groupId) {
        this.activityId = activityId;
        this.groupId = groupId;
        this.random = new Random();
        this.unionDataMap = new ConcurrentHashMap<>();
        this.userDataMap = new ConcurrentHashMap<>();
        this.trackDataMap = new ConcurrentHashMap<>();
        this.rankDataListMap = new ConcurrentHashMap<>();
        this.rankDataMapMap = new ConcurrentHashMap<>();
        loadDb();

    }

    public void loadDb(){
        this.unionDataMap = new CrossHorseRunUnionDataDaoImpl().getCrossHorseRunUnionData(activityId,groupId);
        this.userDataMap = new CrossHorseRunUserDataDaoImpl().getCrossHorseRunUserData(activityId,groupId);
        List<CrossHorseRunZoneRoundRankData> tmpHorseRunZoneRoundRankData = new CrossHorseRunZoneRoundRankDataDaoImpl().getCrossHorseRunZoneRoundRankData(activityId, groupId);
        for (CrossHorseRunZoneRoundRankData rankData : tmpHorseRunZoneRoundRankData) {
            Map<Integer, List<CrossHorseRunZoneRoundRankData>> roundMap = rankDataListMap.computeIfAbsent(rankData.getRoundId(), k -> new ConcurrentHashMap<>());
            List<CrossHorseRunZoneRoundRankData> zoneList = roundMap.computeIfAbsent(rankData.getZone(), k -> new ArrayList<>());
            zoneList.add(rankData);

            Map<Integer, Map<Long, CrossHorseRunZoneRoundRankData>> mapMap = rankDataMapMap.computeIfAbsent(rankData.getRoundId(), k -> new ConcurrentHashMap<>());
            Map<Long, CrossHorseRunZoneRoundRankData> zoneMap = mapMap.computeIfAbsent(rankData.getZone(), k -> new ConcurrentHashMap<>());
            zoneMap.put(rankData.getUserId(), rankData);
        }
        for (Map<Integer,List<CrossHorseRunZoneRoundRankData>> roundMap:rankDataListMap.values()){
            for (List<CrossHorseRunZoneRoundRankData> rankDataList : roundMap.values()){
                rankDataList.sort(Comparator.comparing(CrossHorseRunZoneRoundRankData::getRank));
            }
        }


        trackDataMap = new CrossHorseRunTrackDataDaoImpl().getCrossHorseRunTrackData(activityId,groupId);
        for (CrossHorseRunUserData userData: userDataMap.values()) {
            //查看玩家报名数据 塞入赛道的报名列表中
            Map<Integer, Integer> signData = userData.getSignData();
            for (Map.Entry<Integer,Integer> entry:signData.entrySet()) {
                CrossHorseRunTrackData trackDataByZone = getTrackDataByZone(entry.getKey(), entry.getValue());
                if (trackDataByZone == null){
                    CrossHorseRunMgr.getLogger().error("小马快跑赛道数据未找到,活动id{},分组id{},轮次id{},赛道id{}",activityId, groupId,entry.getKey(),entry.getValue());
                    continue;
                }
                trackDataByZone.addSignMember(userData.getUserId());
            }
        }

    }

    public CrossHorseRunTrackData getTrackDataByZone(int round,int zone){
        Map<Integer, CrossHorseRunTrackData> roundMap = trackDataMap.get(round);
        if (roundMap == null) {
            return null;
        }
        return roundMap.get(zone);
    }

    //定时器
    public void roundTask(){
        checkTrackData();
    }

    /**
     * 检测赛场数据
     */
    public synchronized void checkTrackData(){
        HorseRunConfig config = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);
        if (config == null) {
            return;
        }
        //不在活动期了 不管了
        ActivityInfo activityInfo = config.getActivityInfo();
        if (!ActivityMgr.activityInTime(activityInfo)){
            return;
        }
        //今天是什么天
        int nowDay = config.getTodayRound();
        //如果今天数据还没生成 去生一下
        if (!trackDataMap.containsKey(nowDay)){
            synchronized(trackDataMap){
                if (!trackDataMap.containsKey(nowDay)){
                    Map<Integer, CrossHorseRunTrackData> map = generateTodayRunTrackDataMap(nowDay, config);
                    if (map != null && map.size() == 4){
                        trackDataMap.put(nowDay, map);
                    }else {
                        CrossHorseRunMgr.getLogger().error("小马快跑生成赛道数据错误,活动id{},分组id{}",activityId,groupId);
                        return;
                    }
                }
            }
        }
        //获取今天的所有赛道
        Map<Integer, CrossHorseRunTrackData> map = trackDataMap.get(nowDay);
        //是否需要商会重新计算分数
        boolean needUnionRecalculate = false;
        for (CrossHorseRunTrackData trackData : map.values()) {
            //结算了的不管
            if (trackData.isSettlement()){
                continue;
            }

            //如果当前大于结算时间 这里多给了一分钟 不然怕报名的正好上来
            if (System.currentTimeMillis() > trackData.getNeedSettlementTime()){
                boolean success = settlementTrack(trackData, config);
                if (success){
                    needUnionRecalculate = true;
                }
            }
        }
        //如果需要重算 所有商会拿出来算一下
        if (needUnionRecalculate){
            for (CrossHorseRunUnionData unionData:unionDataMap.values()){
                synchronized (unionData){
                    recalculateUnionRoundScore(unionData,nowDay);
                }
            }
            notifyServerUpdateCondition();
        }

    }

    /**
     * 通知服务器在线玩家刷新一下成就
     */
    public void notifyServerUpdateCondition(){
        UnionActivityGroup groupData = Cross2UnionActivityGroupMgr.getGroupData(activityId, groupId);
        Set<Long> serverSet = groupData.getServerSet();

        HorseRunProto.CrossHorseRunNotifyUserUpdateCondition.Builder builder = HorseRunProto.CrossHorseRunNotifyUserUpdateCondition.newBuilder();
        builder.setActivityId(activityId);
        builder.setGroup(groupId);

        for (long serverId : serverSet){

//            YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_HORSE_RUN_NOTICE_PLAYER_UPDATE_CONDITION, builder);
//            MessageHelper.sendPacket(serverId,0,yanQuMessage);
        }
    }


    /**
     * 结算一下赛道
     */
    public boolean settlementTrack(CrossHorseRunTrackData trackData, HorseRunConfig config){
        List<CrossHorseRunZoneRoundRankData> rankDataList = new ArrayList<>();
        //防止这时候还有人报名之类的
        synchronized (trackData){
            if (trackData.isSettlement()){
                return false;
            }

            for (long userId:trackData.getJoinMember()){
                CrossHorseRunUserData userData = getUserData(userId);
                if (userData == null){
                    CrossHorseRunMgr.getLogger().error("小马快跑玩家数据未找到,活动id{},分组id{},玩家id{}",activityId, groupId,userId);
                    continue;
                }
                Map<Integer, Integer> totalAttr = userData.getTotalAttr();
                BigDecimal time = calRunUseTime(trackData, totalAttr, config);
                CrossHorseRunZoneRoundRankData rankData = new CrossHorseRunZoneRoundRankData();
                rankData.setUserId(userId);
                rankData.setActivityId(activityId);
                rankData.setGroupId(groupId);
                rankData.setRoundId(trackData.getDay());
                rankData.setZone(trackData.getZone());
                rankData.setRank(-1);
                rankData.setHistoryEarn(getHistoryMaxEarn(userId));
                rankData.setFinishTime(time);

                rankData.setLockAttr(totalAttr);

                rankData.setInsertOption();

                rankDataList.add(rankData);
            }
            //排名一下
            resortRank(rankDataList,config);
            //设置结算成功
            trackData.setIsSettlement(true);
        }
        //更新玩家排行结算
        updateUserRankResult(rankDataList,config);

        Map<Integer, List<CrossHorseRunZoneRoundRankData>> roundMap = rankDataListMap.computeIfAbsent(trackData.getDay(), k -> new ConcurrentHashMap<>());
        roundMap.put(trackData.getZone(), rankDataList);

        Map<Integer, Map<Long, CrossHorseRunZoneRoundRankData>> roundIdxMap = rankDataMapMap.computeIfAbsent(trackData.getDay(), k -> new ConcurrentHashMap<>());
        Map<Long, CrossHorseRunZoneRoundRankData> zoneMap = roundIdxMap.computeIfAbsent(trackData.getZone(), k -> new ConcurrentHashMap<>());
        for (CrossHorseRunZoneRoundRankData data : rankDataList){
            zoneMap.put(data.getUserId(), data);
        }

        return true;
    }

    /**
     * 更新排名到玩家身上
     */
    public void updateUserRankResult(List<CrossHorseRunZoneRoundRankData> rankDataList, HorseRunConfig config){
        //更新玩家数据
        for (CrossHorseRunZoneRoundRankData data:rankDataList){
            CrossHorseRunUserData userData = getUserData(data.getUserId());
            if (userData == null){
                CrossHorseRunMgr.getLogger().error("小马快跑玩家数据未找到,活动id{},分组id{},玩家id{}",activityId, groupId,data.getUserId());
                continue;
            }
            synchronized (userData){
                //更新到玩家跨服数据
                updateRankToUser(data,userData,config);
                //更新排行榜
                changeUserRank(userData);
            }
            Map<Integer, Integer> attrLevelMap = userData.getAttrLevelMap();
            LogHorseRunRacingResult logHorseRunRacingResult = new LogHorseRunRacingResult
                    (activityId,groupId,data.getZone(),userData.getUserId(),userData.getUnionId(),userData.getNowGrade(),
                            attrLevelMap.getOrDefault(1,0),
                            attrLevelMap.getOrDefault(1,0),
                            attrLevelMap.getOrDefault(1,0),
                            new HashMap<Integer,Integer>(data.getLockAttr()),
                            new ArrayList<>(userData.getSkillList()),
                            data.getRank(),
                            (int) config.getRacingScoreByRank(data.getRoundId(),data.getRank())
                            );
            CrossAutoLogMgr.add(logHorseRunRacingResult);
        }
    }

    /**
     * 排名
     * @param rankDataList
     * @param config
     */

    public void resortRank(List<CrossHorseRunZoneRoundRankData> rankDataList, HorseRunConfig config){
        rankDataList.sort(new Comparator<CrossHorseRunZoneRoundRankData>() {
            @Override
            public int compare(CrossHorseRunZoneRoundRankData o1, CrossHorseRunZoneRoundRankData o2) {

                int compare = o1.getFinishTime().compareTo(o2.getFinishTime());
                if (compare == 0){
                    return o2.getHistoryEarn().compareTo(o1.getHistoryEarn());
                }else {
                    return compare;
                }
            }
        });
        int rank = 1;
        for (CrossHorseRunZoneRoundRankData rankData : rankDataList){
//            if (rank >config.getRankMaxNum()){
//                break;
//            }
            rankData.setRank(rank);
            rank++;
        }

    }

    /**
     * 商会重新计算某一个轮次的积分
     */
    public void recalculateUnionRoundScore(CrossHorseRunUnionData unionData, int round) {

        List<Long> member = new ArrayList<>(unionData.getJoinMember());
        long totalScore = 0;
        for (long userId : member) {
            CrossHorseRunUserData userData = getUserData(userId);
            if (userData == null) {
                CrossHorseRunMgr.getLogger().error("小马快跑玩家数据未找到,活动id{},分组id{},玩家id{}", activityId, groupId, userId);
                continue;
            }
            long roundScore = userData.getRoundScore(round);
            totalScore += roundScore;
        }
        unionData.getTotalAchievementScore().put(round, totalScore);
        unionData.setUpdateOption();
    }


    /**
     * 更新排行数据和积分获取到玩家身上
     */
    public void updateRankToUser(CrossHorseRunZoneRoundRankData rankData, CrossHorseRunUserData userData, HorseRunConfig config) {

        int racingScoreByRank = (int) config.getRacingScoreByRank(rankData.getRoundId(),rankData.getRank());
        userData.addHorseRunRacingUserResult(rankData.getRoundId(), rankData.getZone(), rankData.getRank(), racingScoreByRank,rankData.getFinishTime().longValue());
    }

    /**
     * 个人积分榜变更
     */
    public void changeUserRank(CrossHorseRunUserData userData){
        //玩家所有轮次总分
        long totalScore = userData.getTotalScore();

        UnionBaseInfo unionBaseInfo = null;

        UnionActivityGroupUnion unionData = Cross2UnionActivityGroupMgr.getUnionData(activityId, userData.getUnionId());
        ConcurrentHashMap<Long, Integer> memberMap = new ConcurrentHashMap<>();
        if (unionData != null){
            unionBaseInfo = unionData.getUnionBaseInfo();
            //职位map
            for (UnionActivityGroupUser groupUser : unionData.getUserMap().values()) {
                memberMap.put(groupUser.getUserId(), groupUser.getPosition());
            }
        }



        UserYRank userYRank = new UserYRank();
        userYRank.setUserId(userData.getUserId());
        userYRank.setActivityId(userData.getActivityId());
        userYRank.setGroupId(userData.getGroupId());
        userYRank.setIdKey(String.valueOf(eGamePlayerEventType.HorseRunUnionRacingScoreRank.getValue()));
        userYRank.setValue(BigInteger.valueOf(totalScore));
        userYRank.setUpdateTime(System.currentTimeMillis());
        userYRank.setUserBaseInfo(CrossUserMgr.getUserBaseInfo(userData.getUserId()));

        CrossYRankMgr.unionUserRankChange(userYRank,userData.getUnionId(),unionBaseInfo,memberMap, UnionRiseRankArgs.NOTIFY_TYPE_NORMAL);
    }


    /**
     * 获取某个玩家的历史最高赚钱 只用来排名 拿不到无所谓
     */
    public BigInteger getHistoryMaxEarn (long userId ){
        CrossUserBaseInfo crossUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId);
        if (crossUserBaseInfo == null){
            return BigInteger.ZERO;
        }else {
            return crossUserBaseInfo.getUserBaseInfo().getEarnSpeed();
        }
    }

    /**
     * 计算玩家跑某一条赛道需要多久
     */
    public BigDecimal calRunUseTime(CrossHorseRunTrackData trackData,Map<Integer, Integer> totalAttr,HorseRunConfig config){
        Map<Integer, Integer> energyTrackAttrAddMap = config.getEnergyTrackAttrAddMap();
        BigDecimal energyRoadSpeed = BigDecimal.valueOf((
                (long) totalAttr.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1) * energyTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1))
                +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1) * energyTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1))
                +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1) * energyTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1)))
                .divide(BigDecimal.valueOf(1000),2, RoundingMode.UP);

        Map<Integer, Integer> artfulTrackAttrAddMap = config.getArtfulTrackAttrAddMap();
        BigDecimal artFulRoadSpeed = BigDecimal.valueOf((
                        (long) totalAttr.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1) * artfulTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1))
                        +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1) * artfulTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1))
                        +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1) * artfulTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1)))
                .divide(BigDecimal.valueOf(1000),2, RoundingMode.UP);

        Map<Integer, Integer> resistanceTrackAttrAddMap = config.getResistanceTrackAttrAddMap();
        BigDecimal resistanceRoadSpeed = BigDecimal.valueOf((
                        (long) totalAttr.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1) * resistanceTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.energy.getValue(),1))
                        +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1) * resistanceTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.artful.getValue(),1))
                        +((long) totalAttr.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1) * resistanceTrackAttrAddMap.getOrDefault(eHorseRunAttrEnum.resistance.getValue(),1)))
                .divide(BigDecimal.valueOf(1000),2, RoundingMode.UP);

        BigDecimal energyTime = BigDecimal.valueOf(trackData.getAttrTotalLength().get(eHorseRunAttrEnum.energy.getValue())).divide(energyRoadSpeed, 8, RoundingMode.UP);
        BigDecimal artTime = BigDecimal.valueOf(trackData.getAttrTotalLength().get(eHorseRunAttrEnum.artful.getValue())).divide(artFulRoadSpeed, 8, RoundingMode.UP);
        BigDecimal resistanceTime = BigDecimal.valueOf(trackData.getAttrTotalLength().get(eHorseRunAttrEnum.resistance.getValue())).divide(resistanceRoadSpeed, 8, RoundingMode.UP);

        BigDecimal totalTime = energyTime.add(artTime).add(resistanceTime);
        return totalTime;
    }



    /**
     * 生成当天的四条赛道
     * @param nowDay
     * @param config
     * @return
     */
    public Map<Integer, CrossHorseRunTrackData> generateTodayRunTrackDataMap(int nowDay,HorseRunConfig config){

        Map<Integer, CrossHorseRunTrackData> runTrackDataMap = new ConcurrentHashMap<>();
        CrossHorseRunMgr.getLogger().debug("小马快跑 活动id{},分组id{},天数{}生成赛道中",activityId, groupId,nowDay);
        for (eHorseRunRacingZoneEnum zoneEnum :eHorseRunRacingZoneEnum.values()){
            CrossHorseRunTrackData trackData = new CrossHorseRunTrackData();
            trackData.setActivityId(activityId);
            trackData.setGroupId(groupId);
            trackData.setDay(nowDay);
            trackData.setZone(zoneEnum.getValue());
            //赛道类型 123 value 上下限
            Map<Integer, List<Integer>> map = config.getRacingTrackDistribute(zoneEnum);
            if (null == map){
                return null;
            }
            CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中",zoneEnum.getName());
            //各个属性总长度的map
            Map<Integer,Integer> attrTotalMap = new ConcurrentHashMap<>();
            //所有属性的分块
            List<HorseRunTrackPartData> partDataList = new ArrayList<>();

            int hasUsedNum = 0;
            int lengthNum = 0;
            int realLength = 0;

            for (eHorseRunAttrEnum attrEnum :eHorseRunAttrEnum.values()){
                int attrType = attrEnum.getValue();
                if (attrEnum != eHorseRunAttrEnum.resistance){
                    List<Integer> value = map.get(attrType);

                    int min = value.get(0);
                    int max = value.get(1);
                    //长度数量 例如40 - 60 ->55
                    lengthNum = random.nextInt(max - min+1) + min;
                    //当前类型赛道的总长度 比如精力赛道总长度

                    //记录在案
                    hasUsedNum+=lengthNum;
                }else {
                    //第三条赛道是总长度扣下来前两条合
                    int racingRoadTotalNum = config.getRacingRoadTotalNum();
                    lengthNum = racingRoadTotalNum - hasUsedNum;
                }

                realLength = lengthNum * config.getTrackLengthRate();
                CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中,该属性总长度为{}",zoneEnum.getName(),realLength);

                attrTotalMap.put(attrType, realLength);
                //当前类型赛道分段的最大值和最小值
                List<Integer> trackSegmentationById = config.getTrackSegmentationById(attrType);
                int minSegmentation = trackSegmentationById.get(0);
                int maxSegmentation = trackSegmentationById.get(1);
                //算出分了多少段
                int segmentation = 1;
                if (minSegmentation == maxSegmentation){
                    segmentation = minSegmentation;
                }else {
                    segmentation= random.nextInt(maxSegmentation - minSegmentation + 1) + minSegmentation;
                }

                //如果分完赛道都小于1了 炸了
                if (segmentation > lengthNum){
                    segmentation = lengthNum;
                }

                CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中,该属性分段为{}",zoneEnum.getName(),segmentation);
                //随机出六个数字
                List<Integer> differentRandomNum = new ArrayList<>();
                if (segmentation > 1){
                    differentRandomNum = RandomHelper.getDifferentRandomNum(lengthNum - 1, segmentation - 1);
                } else {
                    differentRandomNum.add(lengthNum-1);
                }

                //全部+1
                for (int i = 0;i<differentRandomNum.size();i++){
                    differentRandomNum.set(i,differentRandomNum.get(i)+1);
                }

                //从小到大排序
                Collections.sort(differentRandomNum);
                CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中,该属性数字为{}",zoneEnum.getName(),differentRandomNum);

                if(differentRandomNum.size()==1){
                    int realSegLength = differentRandomNum.get(0)*config.getTrackLengthRate();
                    HorseRunTrackPartData partData = new HorseRunTrackPartData(attrType,realSegLength);
                    partDataList.add(partData);
                    CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中,分段属性{},分段长度为{}",zoneEnum.getName(),attrType,realSegLength);
                }else {
                    for (int i = 0;i<=differentRandomNum.size();i++){
                        int realSegLength;
                        if (i == 0){
                            realSegLength = differentRandomNum.get(i) * config.getTrackLengthRate();
                        }else if (i == differentRandomNum.size()){
                            realSegLength = (lengthNum - differentRandomNum.get(i-1)) * config.getTrackLengthRate();
                        }else {
                            realSegLength = (differentRandomNum.get(i) - differentRandomNum.get(i-1))* config.getTrackLengthRate();
                        }

                        HorseRunTrackPartData partData = new HorseRunTrackPartData(attrType,realSegLength);
                        partDataList.add(partData);
                        CrossHorseRunMgr.getLogger().debug("生成赛道类型{}中,分段属性{},分段长度为{}",zoneEnum.getName(),attrType,realSegLength);
                    }
                }
            }
            //打乱
            Collections.shuffle(partDataList);
            trackData.setPartData(partDataList);
            trackData.setAttrTotalLength(attrTotalMap);

            int totalLength = 0;
            for (int length: attrTotalMap.values()){
                totalLength += length;
            }
            trackData.setTotalLength(totalLength);
            trackData.setIsSettlement(false);
            trackData.setInsertOption();
            //设置结算时间为等待开赛结束一分钟后 todo hyq
            trackData.setNeedSettlementTime(DateHelper.getTodayZeroTimeStamp() + (config.getOpenRacingTimeList().get(2)+1)*DateHelper.MINUTE_MILLIONS);
            runTrackDataMap.put(zoneEnum.getValue(),trackData);

        }
        return runTrackDataMap;

    }


    public CrossHorseRunUserData getUserData(long userId) {
        if (userDataMap.containsKey(userId)) {
            return userDataMap.get(userId);
        }
        return null;
    }

    /**
     * 获取商会经验和马场信息
     */
    public HorseRunProto.HorseRunGetUnionRanchDataAndExpResp.Builder getUnionRanchDataAndGetExp(long userId,int needRandomHorse) {
        HorseRunProto.HorseRunGetUnionRanchDataAndExpResp.Builder resp = HorseRunProto.HorseRunGetUnionRanchDataAndExpResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null) {
            resp.setRet(GameErrorCode.E_HORSE_RUN_ACTIVITY_USER_DATA_ERROR) ;
            return resp;
        }
        CrossHorseRunUnionData unionData = getUnionData(userData.getUnionId());
        if (unionData == null) {
            resp.setRet(GameErrorCode.E_HORSE_RUN_ACTIVITY_NO_LOCK_UNION) ;
            return resp;
        }
        HorseRunConfig horseRunConfig = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);
        if (horseRunConfig == null) {
            resp.setRet(GameErrorCode.E_HORSE_RUN_CONFIG_ERROR);
            return resp;
        }
        int unionLevel = unionData.getUnionLevel();
        HorseRunRaceCourseConfig courseConfigById = horseRunConfig.getCourseConfigById(unionLevel);
        if (courseConfigById == null) {
            resp.setRet(GameErrorCode.E_HORSE_RUN_CONFIG_ERROR);
            return resp;
        }


        resp.setRet(0);
        //离线时间
        resp.setGameOffTime(System.currentTimeMillis() - userData.getLastGetExpTime());
        //马场数据
        resp.setRanchData(parseHorseRunRanchData(unionData,needRandomHorse == 0 ?0:horseRunConfig.getShowUnionHorseNum(),userId));
        //获得的经验分钟数
        synchronized (userData){
            long expMinutes = calAddExpMinutes(userData, horseRunConfig.getExpOutPutNeedMinute());
            //获得经验是
            long expAdd = expMinutes * courseConfigById.getExp();
            //离线的时候商会升级了
            if (userData.getCacheExp() > 0){
                expAdd += userData.getCacheExp();
                userData.setCacheExp(0);
            }
            resp.setAddExp(expAdd);
        }
        return resp;
    }

    /**
     * 计算获得的经验 返回值是经验的数量
     */
    public long calAddExpMinutes(CrossHorseRunUserData userData, int expNeedMinute) {
        long now = System.currentTimeMillis();

        long lastGetExpTime = userData.getLastGetExpTime();
        long expNum = (now - lastGetExpTime) / (expNeedMinute * DateHelper.MINUTE_MILLIONS);
        if (expNum > 0) {
            userData.setLastGetExpTime(lastGetExpTime + (expNum * expNeedMinute * DateHelper.MINUTE_MILLIONS));
//            CrossHorseRunMgr.getLogger().error("当前时间{},玩家上次时间{},更新时间{},一共获得{}分钟",now,lastGetExpTime,userData.getLastGetExpTime(),expNum);
        }
        return expNum;

    }


    /**
     * 玩家上传小马数据
     * @param userId
     * @param briefData
     * @return
     */
    public CrossHorseRunUserData uploadUserData(long userId, HorseRunProto.HorseBriefData briefData) {


        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null) {
            UnionActivityGroupUnion unionData = Cross2UnionActivityGroupMgr.getUnionData(activityId, userId);
            if (unionData == null) {
                CrossHorseRunMgr.getLogger().error("horse run activity player unionData is null!!!! playerId{}",userId);
                return null;
            }
            synchronized (userDataMap){
                userData = getUserData(userId);
                if (userData == null) {
                    userData = initUserData(userId, briefData,unionData.getUnionUid());
                }
            }
            if (userData != null) {
                putUserIntoUnion(userId,unionData.getUnionUid());
            }

        }else {
            updateUserData(userData, briefData);

        }
        //更新商会的经验
        if (userData != null) {
            checkUnionAllExp(userData.getUnionId());
        }
        return userData;
    }

    /**
     * 重新计算商会经验 检测是否升级
     */
    public void checkUnionAllExp(String unionId){
        CrossHorseRunUnionData unionData = getUnionData(unionId);
        if (unionData == null) {
            return;
        }

        //先锁商会
        synchronized (unionData){
            Set<Long> joinMember = unionData.getJoinMember();
            long totalGrade = 0;
            for (long userId : joinMember) {
                CrossHorseRunUserData userData = getUserData(userId);
                if (userData == null) {
                    CrossHorseRunMgr.getLogger().error("小马快跑玩家数据错误 activityId{},userId{}", activityId, userId);
                    continue;
                }
                totalGrade += userData.getMaxGrade();
            }
            if (totalGrade == unionData.getTotalGrade()) {
                return;
            }


            unionData.setTotalGrade(totalGrade);
            HorseRunConfig horseRunConfig = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);
            if (horseRunConfig == null) {
                return;
            }
            int levelByUnionTotalGrade = horseRunConfig.getLevelByUnionTotalGrade(totalGrade);
            int oldLv = unionData.getUnionLevel();
            //如果升级了 去把玩家经验累计一下
            if (oldLv != levelByUnionTotalGrade) {
                HorseRunRaceCourseConfig courseConfigById = horseRunConfig.getCourseConfigById(oldLv);
                for (long userId : joinMember) {
                    CrossHorseRunUserData userData = getUserData(userId);
                    if (userData == null) {
                        CrossHorseRunMgr.getLogger().error("小马快跑玩家数据错误 没有更新经验数据 activityId{},userId{}", activityId, userId);
                        continue;
                    }
                    synchronized (userData) {
                        long minutes = calAddExpMinutes(userData, horseRunConfig.getExpOutPutNeedMinute());
                        if (minutes <= 0) {
                            continue;
                        }
                        userData.setCacheExp(userData.getCacheExp() + (minutes*courseConfigById.getExp()));
                    }
                }
                unionData.setUnionLevel(levelByUnionTotalGrade);
                //日志
                LogHorseRunUnionCourseLevelUp logHorseRunUnionCourseLevelUp = new LogHorseRunUnionCourseLevelUp(activityId,groupId,unionId,unionData.getTotalGrade(),oldLv,levelByUnionTotalGrade);
                CrossAutoLogMgr.add(logHorseRunUnionCourseLevelUp);
            }
        }
    }



    /**
     * 玩家放入商会中
     */
    public void putUserIntoUnion(long userId,String unionId){
        CrossHorseRunUnionData unionData =getUnionData(unionId);
        if (unionData == null) {
            synchronized (unionDataMap){
                unionData = getUnionData(unionId);
                if (unionData == null) {
                    unionData = initUnionData(unionId);
                }

            }
        }
        if (unionData != null) {
            synchronized (unionData){
                unionData.getJoinMember().add(userId);
            }
            unionData.setUpdateOption();
        }
    }

    /**
     * 更新玩家数据
     * @param userData
     * @param briefData
     */
    public void updateUserData(CrossHorseRunUserData userData,HorseRunProto.HorseBriefData briefData){
        userData.setHorseAppearance(briefData.getAppearance());
        userData.setEquipment(briefData.getHorseRunEquipList());
        userData.setNowGrade(briefData.getGrade());
        //大于最大才更新
        if (briefData.getGrade() > userData.getMaxGrade()){
            userData.setMaxGrade(briefData.getGrade());
        }
        userData.setSkillList(briefData.getSkillList());
        userData.setAttrLevelByList(briefData.getPointAttrLevelList());
        userData.setExtAttrByList(briefData.getExtAttrList());
        userData.setTotalAttrByList(briefData.getAttrList());
        userData.setLevel(briefData.getLevel());
    }

    /**
     * 初始化用户数据
     * @param userId
     * @param briefData
     * @return
     */

    public CrossHorseRunUserData initUserData(long userId,HorseRunProto.HorseBriefData briefData,String unionId) {

        CrossHorseRunUserData userData = new CrossHorseRunUserData(activityId, groupId,userId,unionId);
        userData.setHorseAppearance(briefData.getAppearance());
        userData.setEquipment(briefData.getHorseRunEquipList());
        userData.setNowGrade(briefData.getGrade());
        userData.setMaxGrade(briefData.getGrade());
        userData.setSkillList(briefData.getSkillList());
        userData.setAttrLevelByList(briefData.getPointAttrLevelList());
        userData.setTotalAttrByList(briefData.getAttrList());
        userData.setExtAttrByList(briefData.getExtAttrList());
        userData.setSignData(new ConcurrentHashMap<>());
        userData.setLevel(briefData.getLevel());
        userData.setCacheExp(0);
        userData.setLastGetExpTime(System.currentTimeMillis());
        userData.setRacingResult(new ConcurrentHashMap<>());

        userData.setInsertOption();
        userDataMap.put(userId, userData);
        return userData;
    }

    /**
     * 初始化商会数据
     * @param unionId
     * @return
     */

    public CrossHorseRunUnionData initUnionData(String unionId) {
        CrossHorseRunUnionData unionData = new CrossHorseRunUnionData();
        unionData.setActivityId(activityId);
        unionData.setGroupId(groupId);
        unionData.setUnionId(unionId);
        unionData.setUnionLevel(1);
        unionData.setTotalAchievementScore(new ConcurrentHashMap<>());
        unionData.setJoinMember(new ConcurrentHashSet<>());

        unionData.setInsertOption();
        unionDataMap.put(unionId,unionData);
        return unionData;
    }


    public List<CrossHorseRunUnionData> getUnionDataList() {
        List<CrossHorseRunUnionData> list = new ArrayList<CrossHorseRunUnionData>();
        synchronized (unionDataMap) {
            list.addAll(unionDataMap.values());
        }
        return list;
    }

    public List<CrossHorseRunUserData> getUserDataList() {
        List<CrossHorseRunUserData> list = new ArrayList<>();
        synchronized (userDataMap) {
            list.addAll(userDataMap.values());
        }
        return list;
    }

    public List<CrossHorseRunTrackData> getTrackDataList() {
        List<CrossHorseRunTrackData> list = new ArrayList<>();
        synchronized (trackDataMap) {
            for (Map<Integer, CrossHorseRunTrackData> map: trackDataMap.values()){
                list.addAll(map.values());
            }
        }
        return list;
    }

    public List<CrossHorseRunZoneRoundRankData> getZoneRoundRankDataList() {
        List<CrossHorseRunZoneRoundRankData> list = new ArrayList<>();
        synchronized (rankDataListMap){
            for (Map<Integer,List<CrossHorseRunZoneRoundRankData>> map:rankDataListMap.values()){
                for (List<CrossHorseRunZoneRoundRankData> rankDataList:map.values()){
                    list.addAll(rankDataList);
                }
            }
        }
        return list;
    }


    public void save(){
        List<CrossHorseRunTrackData> trackDataList = getTrackDataList();
        for (CrossHorseRunTrackData trackData: trackDataList){
            if (trackData.isInsertOption()){
                new CrossHorseRunTrackDataDaoImpl().add(trackData);
            }else if (trackData.isUpdateOption()){
                new CrossHorseRunTrackDataDaoImpl().update(trackData);
            }
        }

        List<CrossHorseRunUnionData> unionDataList = getUnionDataList();
        for (CrossHorseRunUnionData unionData: unionDataList){
            if (unionData.isInsertOption()){
                new CrossHorseRunUnionDataDaoImpl().add(unionData);
            }else if (unionData.isUpdateOption()){
                new CrossHorseRunUnionDataDaoImpl().update(unionData);
            }
        }

        List<CrossHorseRunUserData> userDataList = getUserDataList();
        for (CrossHorseRunUserData userData:userDataList){
            if (userData.isInsertOption()){
                new CrossHorseRunUserDataDaoImpl().add(userData);
            }else if (userData.isUpdateOption()){
                new CrossHorseRunUserDataDaoImpl().update(userData);
            }
        }

        List<CrossHorseRunZoneRoundRankData> zoneRoundRankDataList = getZoneRoundRankDataList();
        for (CrossHorseRunZoneRoundRankData rankData:zoneRoundRankDataList){
            if (rankData.isInsertOption()){
                new CrossHorseRunZoneRoundRankDataDaoImpl().add(rankData);
            }else if (rankData.isUpdateOption()){
                new CrossHorseRunZoneRoundRankDataDaoImpl().update(rankData);
            }
        }

    }

    public CrossHorseRunUnionData getUnionData(String unionId) {
        if (unionDataMap.containsKey(unionId)){
            return unionDataMap.get(unionId);
        }
        return null;
    }

    /**
     * 转商会马场数据msg
     * @param unionData
     * @param randomHorseNum
     * @return
     */

    public HorseRunProto.HorseRunUnionRanchData.Builder parseHorseRunRanchData(CrossHorseRunUnionData unionData,int randomHorseNum,long userId){
        HorseRunProto.HorseRunUnionRanchData.Builder builder = HorseRunProto.HorseRunUnionRanchData.newBuilder();
        if (unionData == null){
            return builder;
        }
        builder.setTotalGrade(unionData.getTotalGrade());
        builder.setLevel(unionData.getUnionLevel());

        if (randomHorseNum > 0){
            List<Long> member = new ArrayList<>(unionData.getJoinMember());
            //随机一下 要看的小马
            Collections.shuffle(member);
            for (long memberId: member){
                if (memberId == userId){
                    continue;
                }
                CrossHorseRunUserData userData = getUserData(memberId);
                if (userData == null){
                    CrossHorseRunMgr.getLogger().error("玩家小马快跑数据未找到 活动id{},玩家id{}",activityId,memberId);
                    continue;
                }
                HorseRunProto.HorseUserBriefData.Builder userHorse = parseUserAndBriefData(userData);
                if (userHorse == null){
                    continue;
                }

                builder.addRandomUserHorse(userHorse);

                if (builder.getRandomUserHorseList().size() >= randomHorseNum){
                    break;
                }
            }
        }
        return builder;
    }

    /**
     * 转化玩家+小马数据builder
     */
    public HorseRunProto.HorseUserBriefData.Builder parseUserAndBriefData(CrossHorseRunUserData userData){


        CrossUserBaseInfo crossUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userData.getUserId());
        if (crossUserBaseInfo == null){
            CrossHorseRunMgr.getLogger().error("玩家小马快跑UserBaseInfo数据未找到 活动id{},玩家id{}",activityId,userData.getUserId());
            return null;
        }

        HorseRunProto.HorseUserBriefData.Builder userHorse = HorseRunProto.HorseUserBriefData.newBuilder();


        HorseRunProto.HorseBriefData.Builder userBuild = parseBriefData(userData);
        userHorse.setBriefData(userBuild);
        userHorse.setUserId(userData.getUserId());

        PlayerProto.PlayerBaseTempMsg.Builder userBaseBuild = PlayerBasePb.parsePlayerBaseTempMsg(crossUserBaseInfo.getUserBaseInfo());
        userHorse.setBaseMsg(userBaseBuild);
        return userHorse;
    }


    /**
     * 转小马数据msg
     * @param userData
     * @return
     */

    public HorseRunProto.HorseBriefData.Builder parseBriefData(CrossHorseRunUserData userData){
        HorseRunProto.HorseBriefData.Builder builder = HorseRunProto.HorseBriefData.newBuilder();
        builder.addAllHorseRunEquip(userData.getEquipment());

        builder.setLevel(userData.getLevel());

        builder.addAttr(userData.getTotalAttr().getOrDefault(eHorseRunAttrEnum.energy.getValue(),0));
        builder.addAttr(userData.getTotalAttr().getOrDefault(eHorseRunAttrEnum.artful.getValue(),0));
        builder.addAttr(userData.getTotalAttr().getOrDefault(eHorseRunAttrEnum.resistance.getValue(),0));

        builder.addPointAttrLevel(userData.getAttrLevelMap().getOrDefault(eHorseRunAttrEnum.energy.getValue(),0));
        builder.addPointAttrLevel(userData.getAttrLevelMap().getOrDefault(eHorseRunAttrEnum.artful.getValue(),0));
        builder.addPointAttrLevel(userData.getAttrLevelMap().getOrDefault(eHorseRunAttrEnum.resistance.getValue(),0));

        builder.setGrade(userData.getNowGrade());
        builder.addAllSkill(userData.getSkillList());
        builder.setAppearance(userData.getHorseAppearance());

        builder.addExtAttr(userData.getExtAttr().getOrDefault(eHorseRunAttrEnum.energy.getValue(),0));
        builder.addExtAttr(userData.getExtAttr().getOrDefault(eHorseRunAttrEnum.artful.getValue(),0));
        builder.addExtAttr(userData.getExtAttr().getOrDefault(eHorseRunAttrEnum.resistance.getValue(),0));
        return builder;
    }

    /**
     * 获取商会奖牌数据
     */
    public HorseRunProto.HorseRunGetUnionMedalDataResp.Builder getUnionMedalData(long userId,int roundId,String unionId){
        HorseRunProto.HorseRunGetUnionMedalDataResp.Builder builder = HorseRunProto.HorseRunGetUnionMedalDataResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return builder;
        }
        CrossHorseRunUnionData unionData;
        if (StringUtils.isNullOrEmpty(unionId)){
            unionData = getUnionData(userData.getUnionId());
        }else {
            unionData = getUnionData(unionId);
        }

        if (unionData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_UNION_DATA_ERROR);
            return builder;
        }
        builder.setRet(0);
        Set<Long> joinMember = unionData.getJoinMember();
        for (long memberId: joinMember){
            CrossHorseRunUserData memberData = getUserData(memberId);
            if (memberData == null){
                CrossHorseRunMgr.getLogger().error("小马快跑玩家数据错误 userId{},activityId{}",memberId,activityId);
                continue;
            }
            Map<Integer, Integer> signData = memberData.getSignData();
            //没参加
            if (signData == null||!signData.containsKey(roundId)){
                continue;
            }
            //看看结束没有 没结束没这个数据
            Map<Integer, HorseRunRacingUserResult> racingResult = memberData.getRacingResult();
            if (racingResult == null||!racingResult.containsKey(roundId)){
                continue;
            }
            //玩家数据
            CrossUserBaseInfo crossUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(memberId);
            if (crossUserBaseInfo == null){
                CrossHorseRunMgr.getLogger().error("玩家小马快跑UserBaseInfo数据未找到 活动id{},玩家id{}",activityId,memberId);
                continue;
            }

            HorseRunRacingUserResult horseRunRacingUserResult = racingResult.get(roundId);

            HorseRunProto.HorseRunUnionMemberMedalData.Builder memberBuild = HorseRunProto.HorseRunUnionMemberMedalData.newBuilder();
            memberBuild.setUserId(memberId);
            PlayerProto.PlayerBaseTempMsg.Builder userBaseBuild = PlayerBasePb.parsePlayerBaseTempMsg(crossUserBaseInfo.getUserBaseInfo());
            memberBuild.setUserBaseInfo(userBaseBuild);
            memberBuild.setZoneType(horseRunRacingUserResult.getZoneId());
            memberBuild.setRank(horseRunRacingUserResult.getRank());
            memberBuild.setScore(horseRunRacingUserResult.getScore());

            builder.addMedalData(memberBuild);
        }
        return builder;

    }

    /**
     * 玩家请求更新商会成就
     * @return
     */

    public HorseRunProto.CrossUserUpdateConditionToGame.Builder userUpdateUnionCondition(long userId){
        HorseRunProto.CrossUserUpdateConditionToGame.Builder builder = HorseRunProto.CrossUserUpdateConditionToGame.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return builder;
        }
        CrossHorseRunUnionData unionData = getUnionData(userData.getUnionId());
        if (unionData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_UNION_DATA_ERROR);
            return builder;
        }
        builder.setRet(0);
        Map<Integer, Long> totalAchievementScore = unionData.getTotalAchievementScore();
        for (Map.Entry<Integer, Long> entry:totalAchievementScore.entrySet()){
            HorseRunProto.CrossUnionScoreData.Builder scoreBuild = HorseRunProto.CrossUnionScoreData.newBuilder();
            scoreBuild.setRound(entry.getKey());
            scoreBuild.setTotalScore(entry.getValue());
            builder.addData(scoreBuild);
        }
        builder.setTotalGrade(unionData.getTotalGrade());
        return builder;

    }

    /**
     * 玩家请求赛道数据
     */
    public HorseRunProto.HorseRunGetRacingTrackResp.Builder getRacingTrack(long userId,int roundId){
        HorseRunProto.HorseRunGetRacingTrackResp.Builder resp = HorseRunProto.HorseRunGetRacingTrackResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            resp.setRet(GameErrorCode.E_HORSE_RUN_ACTIVITY_NO_JOIN_QUALIFICATION);
            return resp;
        }

        if (trackDataMap == null || !trackDataMap.containsKey(roundId)){
            resp.setRet(GameErrorCode.E_HORSE_RUN_DATA_PREPARING);
            return resp;
        }
        resp.setRet(0);
        resp.setMySignTrack(userData.getJoinZone(roundId));
        Map<Integer, CrossHorseRunTrackData> map = trackDataMap.get(roundId);
        for (CrossHorseRunTrackData data:map.values()){
            HorseRunProto.HorseRunRacingTrackData.Builder builder = parseTrackMsg(data);
            resp.addTrackData(builder);
        }
        resp.setLastSignTime(userData.getLastSignTime());
        return resp;
    }

    public HorseRunProto.HorseRunRacingTrackData.Builder parseTrackMsg(CrossHorseRunTrackData data){
        HorseRunProto.HorseRunRacingTrackData.Builder builder = HorseRunProto.HorseRunRacingTrackData.newBuilder();
        builder.setRound(data.getDay());
        builder.setZone(data.getZone());
        builder.setTotalLength(data.getTotalLength());
        builder.setSignUpNum(data.getJoinMember().size());
        for (HorseRunTrackPartData partData:data.getPartData()){
            HorseRunProto.HorseRunRacingTrackPieceData.Builder pieceData = HorseRunProto.HorseRunRacingTrackPieceData.newBuilder();
            pieceData.setType(partData.getType());
            pieceData.setLength(partData.getLength());
            builder.addPieceData(pieceData);
        }
        return builder;

    }

    /**
     * 获取排行榜
     * @param round
     * @param zoneType
     * @return
     */

    public HorseRunProto.HorseRunGetRacingRankDataResp.Builder getRacingRank(int round,int zoneType,long userId){
        HorseRunProto.HorseRunGetRacingRankDataResp.Builder resp = HorseRunProto.HorseRunGetRacingRankDataResp.newBuilder();
        resp.setRet(0);

        HorseRunConfig horseRunConfig = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);

        if (rankDataListMap.containsKey(round)){
            if (rankDataListMap.get(round).containsKey(zoneType)){
                List<CrossHorseRunZoneRoundRankData> tmpRankList = new ArrayList<>(rankDataListMap.get(round).get(zoneType));
                for (CrossHorseRunZoneRoundRankData data:tmpRankList){
                    if (data.getRank() < 0){
                        continue;
                    }
                    if (data.getRank() > horseRunConfig.getRankMaxNum()){
                        continue;
                    }

                    HorseRunProto.HorseRunRankTemp.Builder builder = parseHorseRunRoundZoneRank(data);
                    resp.addRank(builder);
                    if (data.getUserId() == userId){
                        resp.setMyRank(builder);
                    }

                }
            }
        }
        if (!resp.hasMyRank() && rankDataMapMap.containsKey(round)){
            if (rankDataMapMap.get(round).containsKey(zoneType)){
                Map<Long, CrossHorseRunZoneRoundRankData> longCrossHorseRunZoneRoundRankDataMap = rankDataMapMap.get(round).get(zoneType);
                if (longCrossHorseRunZoneRoundRankDataMap.containsKey(userId)){
                    CrossHorseRunZoneRoundRankData rankData = longCrossHorseRunZoneRoundRankDataMap.get(userId);
                    HorseRunProto.HorseRunRankTemp.Builder builder = parseHorseRunRoundZoneRank(rankData);
                    resp.setMyRank(builder);
                }
            }
        }

        return resp;
    }

    /**
     * 转消息体
     * @param data
     * @return
     */

    public HorseRunProto.HorseRunRankTemp.Builder parseHorseRunRoundZoneRank(CrossHorseRunZoneRoundRankData data){
        HorseRunProto.HorseRunRankTemp.Builder builder = HorseRunProto.HorseRunRankTemp.newBuilder();
        builder.setUserId(data.getUserId());
        builder.setRank(data.getRank());
        CrossHorseRunUserData userData = getUserData(data.getUserId());
        if (userData == null){
            return null;
        }
        if (data.getRank() <= 3){
            builder.setHorseData(parseBriefData(userData));
        }

        builder.setValue(data.getFinishTime().longValue());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(data.getUserId());
        if (userBaseInfo == null){
            return null;
        }
        builder.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        UnionActivityGroupUnion unionData = Cross2UnionActivityGroupMgr.getUnionData(activityId, userData.getUnionId());
        builder.setUnionName(unionData == null?"":unionData.getUnionBaseInfo().getUnionName());

        return builder;
    }

    /**
     * 获取他人小马数据
     */
    public HorseRunProto.HorseRunGetOtherHorseDataResp.Builder getOtherHorseData(long targetUserId){
        HorseRunProto.HorseRunGetOtherHorseDataResp.Builder resp = HorseRunProto.HorseRunGetOtherHorseDataResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(targetUserId);
        if (userData == null){
            resp.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return resp;
        }
        resp.setRet(0);
        resp.setData(parseBriefData(userData));
        return resp;

    }

    /**
     * 报名
     */
    public HorseRunProto.HorseRunSignUpRacingResp.Builder signUpRacing(long userId,int zone){
        HorseRunProto.HorseRunSignUpRacingResp.Builder resp = HorseRunProto.HorseRunSignUpRacingResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            resp.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return resp;
        }
        HorseRunConfig config = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);
        int todayRound = config.getTodayRound();


        Map<Integer, CrossHorseRunTrackData> todayTrackMap = trackDataMap.get(todayRound);
        if (todayTrackMap == null){
            resp.setRet(GameErrorCode.E_HORSE_RUN_DATA_PREPARING);
            return resp;
        }
        CrossHorseRunTrackData runTrackData = todayTrackMap.get(zone);
        if (runTrackData == null){
            resp.setRet(GameErrorCode.E_HORSE_RUN_CONFIG_ERROR);
            return resp;
        }
        if (runTrackData.isSettlement()){
            resp.setRet(GameErrorCode.E_HORSE_RUN_NO_SIGN_TIME);
            return resp;
        }

        resp.setRet(0);
        int oldZone = 0;

        synchronized (userData){
            oldZone = userData.getJoinZone(todayRound);
            if (oldZone > 0) {
                if (todayTrackMap.get(oldZone) == null){
                    resp.setRet(GameErrorCode.E_HORSE_RUN_DATA_PREPARING);
                    return resp;
                }

                long now = System.currentTimeMillis();
                if (userData.getLastSignTime() + (DateHelper.SECOND_MILLIONS * config.getRacingChooseResetTime()) > now){
                    resp.setRet(GameErrorCode.E_HORSE_RUN_SIGN_CD);
                    return resp;
                }
            }
            userData.sign(todayRound,zone);
        }

        //如果之前就已经报名过 就要先把老的赛道取消报名
        if(oldZone > 0){
            //取出老赛道
            CrossHorseRunTrackData oldTrackData = todayTrackMap.get(oldZone);
            //先把旧
            synchronized (oldTrackData){
                oldTrackData.removeSignMember(userId);
            }
        }

        //加入新赛道
        synchronized (runTrackData){
            runTrackData.addSignMember(userId);
        }

        resp.setMyTrack(zone);
        resp.setData(parseTrackMsg(runTrackData));
        resp.setLastSignTime(userData.getLastSignTime());
        return resp;
    }

    public HorseRunProto.HorseRunGetNoReadResultResp.Builder getUnreadResult(long userId){
        HorseRunProto.HorseRunGetNoReadResultResp.Builder builder = HorseRunProto.HorseRunGetNoReadResultResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return builder;
        }
        builder.setRet(0);
        int unreadRound = userData.getUnreadRound();
        if (unreadRound != 0){
            HorseRunRacingUserResult horseRunRacingUserResult = userData.getRacingResult().get(unreadRound);
            userData.setUnreadRound(0);
            if (horseRunRacingUserResult == null){

                CrossHorseRunMgr.getLogger().error("玩家查看未读数据丢失,活动id{},分组id{},玩家id{},轮次{}",activityId, groupId,userId,unreadRound);
                return builder;
            }
            HorseRunProto.HorseRunResultJump.Builder jumpBuild = HorseRunProto.HorseRunResultJump.newBuilder();
            jumpBuild.setRound(unreadRound);
            jumpBuild.setMyRank(horseRunRacingUserResult.getRank());
            jumpBuild.setFinishSecond(horseRunRacingUserResult.getTime());
            jumpBuild.setZoneType(horseRunRacingUserResult.getZoneId());
            jumpBuild.setGetScore(horseRunRacingUserResult.getScore());
            builder.setJump(jumpBuild);

        }
        return builder;
    }

    /**
     * 获取商会所有小马数据
     */
    public HorseRunProto.HorseRunGetUnionAllHorseResp.Builder getAllUnionHorseData(long userId){
        HorseRunProto.HorseRunGetUnionAllHorseResp.Builder builder = HorseRunProto.HorseRunGetUnionAllHorseResp.newBuilder();
        CrossHorseRunUserData userData = getUserData(userId);
        if (userData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_USER_DATA_ERROR);
            return builder;
        }
        HorseRunConfig config = CrossHorseRunConfigMgr.getHorseRunConfig(activityId);
        if (config == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CONFIG_ERROR);
            return builder;
        }
        CrossHorseRunUnionData unionData = getUnionData(userData.getUnionId());
        if (unionData == null){
            builder.setRet(GameErrorCode.E_HORSE_RUN_CROSS_UNION_DATA_ERROR);
            return builder;
        }
        builder.setRet(0);

        //今天是什么天
        int nowDay = config.getTodayRound();
        for (long memberId:unionData.getJoinMember()){
            CrossHorseRunUserData memberUserData = getUserData(memberId);
            if (memberUserData == null){
                CrossHorseRunMgr.getLogger().error("玩家小马快跑数据未找到 活动id{},玩家id{}",activityId,memberId);
                continue;
            }
            HorseRunProto.HorseUserBriefData.Builder userHorse = parseUserAndBriefData(memberUserData);
            if (userHorse == null){
                continue;
            }
            userHorse.setJoinZone(memberUserData.getJoinZone(nowDay));
            builder.addBriefData(userHorse);
        }
        return builder;
    }


}
